Redacts a PDF document stored in a stream.
stream
Stream containing an existing PDF document to be redacted.
password
The password to use if stream contains an encrypted PDF file.
redacts
One or more PDF redact objects.
Redaction can be used to remove sensitive information from an existing PDF document.
This method quickly redacts an existing PDF document in place by removing any character, image, or shape that intersects with any of the PDFRedact.Bounds of redacts. The resulting PDF is not re-generated and therefore will maintain the same exact compression, metadata, fonts, and any other resources.
Use the following code to redact all data in a PDF page at location 0, 0 to 100,100:
// Create a PDF redaction object
var redact = new PDFRedact(0, 0, 100, 100);
// Redact the file:
PDFFile.Redact(pdfFileName, new List<PDFRedact> { redact });
using Leadtools.WinForms;
using Leadtools;
using Leadtools.Codecs;
using Leadtools.Controls;
using Leadtools.Drawing;
using Leadtools.ImageProcessing;
using Leadtools.Pdf;
using Leadtools.Svg;
private static void RedactExample()
{
const string toRedact = "LEADTOOLS";
// Make a copy of 'leadtools.pdf' installed with LEADTOOLS
string imagesDir = @"C:\LEADTOOLS22\Resources\Images";
string pdfFileName = Path.Combine(imagesDir, "leadtools-redacted.pdf");
File.Copy(Path.Combine(imagesDir, "leadtools.pdf"), pdfFileName, true);
// We will use PDFDocument to find the position of the words to redact
// Find any text containing the word "LEADTOOLS" in the document
var allWords = new List<MyPDFWord>();
using (var pdfDocument = new PDFDocument(pdfFileName))
{
pdfDocument.ParsePages(PDFParsePagesOptions.Objects, 1, -1);
// Build the words for each page from PDFDocumentPage.Objects
foreach (PDFDocumentPage pdfPage in pdfDocument.Pages)
{
IList<MyPDFWord> words = GetPageWords(pdfPage);
allWords.AddRange(words);
}
}
// Now create a PDFRedact object for each word that contains the value we want to redact
string toRedactLower = toRedact.ToLowerInvariant();
var pdfRedacts = new List<PDFRedact>();
foreach (MyPDFWord word in allWords)
{
if (word.Value.ToLowerInvariant().Contains(toRedactLower))
{
Console.WriteLine($"Found {word.Value} at {word.Bounds} in page {word.PageNumber}");
var pdfRedact = new PDFRedact();
pdfRedact.PageNumber = word.PageNumber;
pdfRedact.Bounds = new PDFRect(word.Bounds.Left, word.Bounds.Top, word.Bounds.Right, word.Bounds.Bottom);
pdfRedacts.Add(pdfRedact);
}
}
// Redact the document
PDFFile.Redact(pdfFileName, null, pdfRedacts);
// Finally, verify that the redact PDF does not have the redacted words anymore
using (var pdfDocument = new PDFDocument(pdfFileName))
{
pdfDocument.ParsePages(PDFParsePagesOptions.Objects, 1, -1);
// Build the words for each page from PDFDocumentPage.Objects
foreach (PDFDocumentPage pdfPage in pdfDocument.Pages)
{
IList<MyPDFWord> words = GetPageWords(pdfPage);
foreach (MyPDFWord word in words)
{
Debug.Assert(!word.Value.ToLowerInvariant().Contains(toRedactLower));
}
}
}
}
// Class to define a word in a PDF page
class MyPDFWord
{
// Page number
public int PageNumber;
// The value as a string
public string Value;
// Its location in the PDF coordinate
public LeadRectD Bounds;
}
private static IList<MyPDFWord> GetPageWords(PDFDocumentPage pdfPage)
{
var words = new List<MyPDFWord>();
IList<PDFObject> objects = pdfPage.Objects;
if (objects == null || objects.Count == 0)
return words;
int objectIndex = 0;
int objectCount = objects.Count;
double pageHeight = pdfPage.Height;
// Loop through all the objects
while (objectIndex < objectCount)
{
// Find the total bounding rectangle, begin and end index of the next word
LeadRectD wordBounds = LeadRectD.Empty;
int firstObjectIndex = objectIndex;
// Loop till we reach EndOfWord or reach the end of the objects
bool more = true;
while (more)
{
PDFObject pdfObject = objects[objectIndex];
// Is it text?
if (pdfObject.ObjectType == PDFObjectType.Text)
{
PDFRect pdfBounds = pdfObject.Bounds;
// objectBounds are in bottom-left coordinate, convert it to top-left
LeadRectD objectBounds = LeadRectD.FromLTRB(pdfObject.Bounds.Left, pageHeight - pdfObject.Bounds.Top, pdfObject.Bounds.Right, pageHeight - pdfObject.Bounds.Bottom);
// Add the bounding rectangle of this object
if (wordBounds.IsEmpty)
wordBounds = objectBounds;
else
wordBounds = LeadRectD.UnionRects(wordBounds, objectBounds);
}
else
{
firstObjectIndex = objectIndex + 1;
}
objectIndex++;
more = (objectIndex < objectCount) && !pdfObject.TextProperties.IsEndOfWord && !pdfObject.TextProperties.IsEndOfLine;
}
if (firstObjectIndex == objectIndex)
{
continue;
}
// From the begin and end index, collect the characters into a string
StringBuilder sb = new StringBuilder();
for (int i = firstObjectIndex; i < objectIndex; i++)
{
if (objects[i].ObjectType == PDFObjectType.Text)
sb.Append(objects[i].Code);
}
// Add this word to the list
PDFObject lastObject = objects[objectIndex - 1];
var word = new MyPDFWord();
word.PageNumber = pdfPage.PageNumber;
word.Value = sb.ToString();
word.Bounds = wordBounds;
words.Add(word);
}
return words;
}